//------------------------------------------------------------------------------
// <copyright file="RpcArchiveImplFactory.cpp" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#include "stdafx.h"

#ifdef ENABLE_GAMESTEST_RPC

#include "RpcArchiveImpl.h"
#include "RpcArchiveImplFactory.h"

using namespace Microsoft::Internal::GamesTest::Rpc::Server;

// Number of internal archive implementations to keep in the pool.
const int RpcArchiveImplFactory::CACHE_SIZE = 8;

// Mutex used to lock resource pool when changing it.
std::mutex RpcArchiveImplFactory::g_implementationLock;

// The resource pool.
RpcArchiveImplFactory::ImplementationFreeList RpcArchiveImplFactory::g_freeList;

/// <summary> 
/// Returns an unused archive implementation from the pool or allocates a new one.
/// </summary>
/// <returns>A pointer to usable archive implementation.</returns>
RpcArchiveImplPtr RpcArchiveImplFactory::Allocate()
{
	std::lock_guard<std::mutex> lock(g_implementationLock);	

	if (g_freeList.empty())
	{
		return RpcArchiveImplPtr(new RpcArchiveImpl(), Release);
	}
	else
	{
		RpcArchiveImpl* nextFreeImpl = g_freeList.top();
		g_freeList.pop();

		_ASSERT(nextFreeImpl != nullptr && "The RpcArchiveImpl retrieved from the pool should never be null.");

		return RpcArchiveImplPtr(nextFreeImpl, Release);
	}
}

/// <summary> 
/// Returns an unused archive implementation from the pool or allocates a new one, then deserializes from Json.
/// </summary>
/// <param name="json">Json node to deserialize from.</param>
/// <returns>A pointer to usable archive implementation.</returns>
RpcArchiveImplPtr RpcArchiveImplFactory::Deserialize(const JsonNode& json)
{
	std::lock_guard<std::mutex> lock(g_implementationLock);	

	if (g_freeList.empty())
	{
		return RpcArchiveImplPtr(new RpcArchiveImpl(json), Release);
	}
	else
	{
		RpcArchiveImpl* nextFreeImpl = g_freeList.top();
		g_freeList.pop();

		_ASSERT(nextFreeImpl != nullptr && "The RpcArchiveImpl retrieved from the pool should never be null.");

		nextFreeImpl->Deserialize(json);

		return RpcArchiveImplPtr(nextFreeImpl, Release);
	}
}

/// <summary> 
/// Releases a previously allocated archive implementation into the pool or destroys if the pool is full.
/// </summary>
/// <param name="pImpl">The previously allocated internal implementation to relase.</param>
void RpcArchiveImplFactory::Release(RpcArchiveImpl* pImpl)
{
	std::lock_guard<std::mutex> lock(g_implementationLock);

	if (g_freeList.size() < CACHE_SIZE)
	{
		pImpl->Clear();
		g_freeList.push(pImpl);
	}
	else
	{
		delete pImpl;
	}
}

#endif // ENABLE_GAMESTEST_RPC